from heapq import *
import sys
from notes import note_from_name
import sched 
import rtmidi
import time 

def note_on( o , ch , note , vel ):
    o.sendMessage( 0x90 | ch , note , vel )
    
def note_off( o , ch , note , vel ):
    o.sendMessage( 0x80 | ch , note , vel )
        

class TrackEventList( object ):
    def __init__(self ):
        self.events = []        
        self.channel = 0 
    def setChannel( self , channel ):
        self.channel = channel
    def addPatchChange( self, time    , patchnum ):
        heappush( self.events , ( time , ( "patch" , self.channel,   patchnum , 0 )) )
    def addNote( self , time ,  note , duration , velocity ):
        heappush( self.events , ( time , ( "on" ,   self.channel , note , velocity )) )
        heappush( self.events , ( time + duration , ( "off" , self.channel ,  note , velocity )) )
    def getEvents( self ):
        ret = []
        while self.events:
            ret.append( heappop ( self.events ))
        return ret
        
class SongEventList( object ):
    def __init__(self):
        self.tracks = {}
        self.tempo = 600000
    def setTempo( self , tempo ):
        self.tempo = tempo
    def addTrack( self , name ):
        if self.tracks.has_key( name ):
            print "A track of that name already exists"
        else:
            self.tracks[ name ] = TrackEventList()
    def __getitem__( self, name):
        if not self.tracks.has_key( name ):
            self.addTrack( name ) 
        return self.tracks[name]            
    def run( self  ):
        o = rtmidi.RtMidiOut()
        o.openPort( 0 )
        s = sched.scheduler( time.time , time.sleep )        
        for track in self.tracks:           
            evts = self.tracks[track].getEvents()
            for item in evts:
                (t , (action , evtchannel ,  note , vel )) = item
                #print t , action , note , vel
                if action=="on":
                    s.enter( t , 1 , note_on , [ o , evtchannel , note_from_name( note ) , vel ] )
                elif action=="off":
                    s.enter( t , 1 , note_off , [ o , evtchannel , note_from_name( note ) , vel ] )
                else:
                    print "Unknown action: " + action
        s.run()     


    

